#include "wc3float.h"
#include "Extern_global_Variable.h"

	//TFloatOperation = function ({out dst: TFloatWar3; constref a: TFloatWar3} constref b: TFloatWar3): PFloatWar3; stdcall; // fastcall
	typedef PSingle (*TFloatOperation) (Pointer Dummy, const Single &a, Single &dst, const Single &b);
	//TIntToFloat = function ({out dst: TFloatWar3; value: Int32}): PFloatWar3; // fastcall
	typedef PFloatWar3 (*TIntToFloat) (Pointer Dummy, Int32 Value, TFloatWar3 &Result); // fastcall

	TFloatOperation _FloatAdd, _FloatSub, _FloatMul, _FloatDiv;
	TIntToFloat _IntToFloat;

//function DoFloatOperation(f: TFloatOperation; const a, b: TFloatWar3): TFloatWar3;
//var
//	MyResult: Single;
//	pa, pb: PFloatWar3;
//begin
//	pa = @a;
//	pb = @b;
//	asm
//		lea ecx, MyResult
//		mov edx, pa
//		mov eax, pb
//		push eax
//		call f
//	end ['ecx', 'edx', 'eax'];
//
//	Result.Value = MyResult;
//end;

TFloatWar3 DoFloatOperation(TFloatOperation f, const TFloatWar3 a, TFloatWar3 b)
{
	TFloatWar3 Result;
	f(NULL, a.Value, Result.Value, b.Value);
	return Result;
};

TFloatWar3 TFloatWar3::operator + (const TFloatWar3 B)
{
	return DoFloatOperation(_FloatAdd, *this, B);
};

TFloatWar3 TFloatWar3::operator - (const TFloatWar3 B)
{
	return DoFloatOperation(_FloatSub, *this, B);
};

TFloatWar3 TFloatWar3::operator-()
{
	TFloatWar3 Result;
	Result.Value = -Value;
	return Result;
};

TFloatWar3 TFloatWar3::operator * (const TFloatWar3 B)
{
	return DoFloatOperation(_FloatMul, *this, B);
};

TFloatWar3 TFloatWar3::operator / (const TFloatWar3 B)
{
	return DoFloatOperation(_FloatDiv, *this, B);
};

Boolean TFloatWar3::operator > (const TFloatWar3 B)
{
	return Value > B.Value;
};

Boolean TFloatWar3::operator >= (const TFloatWar3 B)
{
	return Value >= B.Value;
};

Boolean TFloatWar3::operator < (const TFloatWar3 B)
{
	return Value < B.Value;
};

Boolean TFloatWar3::operator <= (const TFloatWar3 B)
{
	return Value <= B.Value;
};

Boolean TFloatWar3::operator == (const TFloatWar3 B)
{
	return Value == B.Value;
};

/*operator explicit(const A: Int32): TFloatWar3;
begin
	_IntToFloat(NULL, A, Result);
end;

operator explicit(const A: Single): TFloatWar3;
begin
	Result.Value = A;
end;

operator explicit(const A: TFloatWar3): Single;
begin
	Result = A.Value;
end;*/

Boolean TFloatWar3::IsApproximatelyEqualTo(const TFloatWar3 AOther,
	Single Epsilon)
{
	return (*this - AOther).Abs().Value <= Epsilon;
};

TFloatWar3 TFloatWar3::Abs()
{
	TFloatWar3 Result;
	Result.Value = (Single)(*(PDword(&Value)) && 0x7FFFFFFF);
	return Result;
};

procedure w3float_OnInit()
{
	Pointer(_FloatAdd) = Pointer(GameDll + 0x6EF000);
	Pointer(_FloatSub) = Pointer(GameDll + 0x6EEEF0);
	Pointer(_FloatMul) = Pointer(GameDll + 0x6EEE20);
	Pointer(_FloatDiv) = Pointer(GameDll + 0x6EFE10);
	Pointer(_IntToFloat) = Pointer(GameDll + 0x6EF350);
};

void w3float_initialization()
{
	wc3main_SubscribeOnInit(&w3float_OnInit);
}

